#include <windows.h>
#include "toolbox.h"
#include <utility.h>
#include <ansi_c.h>
#include <cvirte.h>
#include <userint.h>
#include "EnumComport.h"
#include "SetupAPI.h"
#include "Ntddser.h"
#include "dbt.h"

static int panelHandle;
static int postHandle;

static int CVICALLBACK OnWmDeviceChange (int panel, int message, unsigned int* wParam, unsigned int* lParam, void* callbackData);

static void ListBoxAddString(char *str);

int main (int argc, char *argv[])
{
	if (InitCVIRTE (0, argv, 0) == 0)
		return -1;	/* out of memory */
	if ((panelHandle = LoadPanel (0, "EnumComport.uir", PANEL)) < 0)
		return -1;
	
	InstallWinMsgCallback(panelHandle, WM_DEVICECHANGE, OnWmDeviceChange, VAL_MODE_INTERCEPT, NULL, &postHandle);
	
	DisplayPanel (panelHandle);
	RunUserInterface ();
	DiscardPanel (panelHandle);
	
	RemoveWinMsgCallback(panelHandle, WM_DEVICECHANGE);
	
	return 0;
}

int CVICALLBACK OnPanel (int panel, int event, void *callbackData,
						 int eventData1, int eventData2)
{
	switch (event)
	{
		case EVENT_GOT_FOCUS:

			break;
		case EVENT_LOST_FOCUS:

			break;
		case EVENT_CLOSE:
			QuitUserInterface (0);
			break;
	}
	return 0;
}

int CVICALLBACK OnRingComport (int panel, int control, int event,
							   void *callbackData, int eventData1, int eventData2)
{
	HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
	SP_DEVINFO_DATA spdata = {0};
	GUID guid = GUID_DEVINTERFACE_COMPORT;

	switch (event)
	{
		case EVENT_LEFT_CLICK:
			ClearListCtrl(panel, control);

			hDevInfo = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
			if(hDevInfo == INVALID_HANDLE_VALUE)
			{
				break;
			}

			spdata.cbSize = sizeof(spdata);
			for(int i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &spdata); i++)
			{
				char buff[1024] = {0};
				if(SetupDiGetDeviceRegistryProperty(hDevInfo, &spdata, SPDRP_FRIENDLYNAME, NULL,
													(PBYTE)buff, 1024, NULL))
				{
					// Prolific com port (COMxx)
					char* p = strstr(buff, "(COM");
					if(p)
					{
						int id = atoi(p + 4);
						// if(p != buff) *(p-1) = '\0';
						InsertListItem(panel, control, -1, buff, id);
					}
				}
			}
			
			SetupDiDestroyDeviceInfoList(hDevInfo);
			break;
	}
	
	return 0;
}

static int CVICALLBACK OnWmDeviceChange (int panel, int message, unsigned int* wParam, unsigned int* lParam, void* callbackData)
{
	PDEV_BROADCAST_HDR p;
	PDEV_BROADCAST_PORT pp;
	char temp[256];
	
	if (message == WM_DEVICECHANGE)
	{
		sprintf(temp, "WM_DEVICECHANGE -> wParam=%x, lParam=%x", *wParam, *lParam);
		ListBoxAddString(temp);
		
		switch (*wParam)
		{
			case DBT_DEVICEARRIVAL:
				p = (PDEV_BROADCAST_HDR)(*lParam);
				if (p->dbch_devicetype == DBT_DEVTYP_PORT)
				{
					pp = (PDEV_BROADCAST_PORT)p;
					sprintf(temp, "  DBT_DEVICEARRIVAL -> %s", pp->dbcp_name);
					ListBoxAddString(temp);
				}
				break;
				
			case DBT_DEVICEREMOVECOMPLETE:
				p = (PDEV_BROADCAST_HDR)(*lParam);
				if (p->dbch_devicetype == DBT_DEVTYP_PORT)
				{
					pp = (PDEV_BROADCAST_PORT)p;
					sprintf(temp, "  DBT_DEVICEREMOVECOMPLETE -> %s", pp->dbcp_name);
					ListBoxAddString(temp);
				}
				break;
		}
		return 1;
	}
	
	return 0;
}

static void ListBoxAddString(char *str)
{
	if (str != NULL && str[0] != '\0')
	{
		int n;
		
		InsertListItem(panelHandle, PANEL_LISTBOX, -1, str, 0);
		GetNumListItems(panelHandle, PANEL_LISTBOX, &n);
		SetCtrlIndex(panelHandle, PANEL_LISTBOX, n - 1);
	}
}
